﻿using System;
using System.Web.Mvc;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using LOMBARDISPICK.Model;
using LOMBARDISPICK.Model.Repositories;
using LOMBARDISPICK.Model.Infrastructure;
using LOMBARDISPICK.Domain.Infrastructure;

using IKVM.Runtime;
using IKVM;
using weka;
using weka.core;
using weka.experiment;
using weka.classifiers.evaluation;

//IKVM.Runtime.dll,IKVM.OpenJDK.core.dll, IKVM.OpenJDK.*.dll


namespace LOMBARDISPICK.Domain.Services
{
	public class PredictionService : IPredictionService
	{
		private readonly INFLTeamsService nflTeamsService;
		private readonly ITeamSeason_1985_2011Service teamSeasonService;

		public PredictionService(
			INFLTeamsService nflTeamsService,
			ITeamSeason_1985_2011Service teamSeasonService
			)
		{
			this.nflTeamsService = nflTeamsService;
			this.teamSeasonService = teamSeasonService;
		}


		////KEY STAS
		//public decimal PasserRating(decimal NFLStat)
		//{
		//    //http://stackoverflow.com/questions/345187/math-mapping-numbers
		//    //Divide to get the ratio between the sizes of the two ranges, then subtract the starting value of your inital range, multiply by the ratio and add the starting value of your second range. In other words,
		//    //I want numbers between 2 and 6 to map to numbers between 10 and 20..
		//    //(20 - 10) / (6 - 2)
		//    //y = (x - 2) * R + 10
		//    if (NFLStat >= 79)
		//    {
		//        decimal ratio = (1.0m - 0.0m) / (158.3m - 79.0m);
		//        decimal coefficient = (NFLStat - 79.0m) * ratio + 0;
		//        return Math.Min(Math.Round(coefficient, 6), 1);
		//    }
		//    else if (NFLStat < 79)
		//    {
		//        decimal ratio = (0.0m - -1.0m) / (79.0m - 0.0m);
		//        decimal coefficient = (NFLStat - 0) * ratio - 1;
		//        return Math.Max(Math.Round(coefficient, 6), -1);
		//    }
		//    else {
		//        //unreachable
		//        return 0;
		//    }
		//}

		//public decimal PointsPerGameOffense(decimal NFLStat)
		//{
		//    if (NFLStat >= 17)
		//    {
		//        decimal ratio = (1.0m - 0.0m) / (40.0m - 17.0m);
		//        decimal coefficient = (NFLStat - 17) * ratio + 0;
		//        return Math.Min(Math.Round(coefficient, 6), 1);
		//    }
		//    else if (NFLStat < 17)
		//    {
		//        decimal ratio = (0.0m - -1.0m) / (17.0m - 2.0m);
		//        decimal coefficient = (NFLStat - 2.0m) * ratio - 1;
		//        return Math.Max(Math.Round(coefficient, 6), -1);
		//    }
		//    else
		//    {
		//        //unreachable
		//        return 0;
		//    }
		//}

		//public decimal PointsPerGameDefense(decimal NFLStat)
		//{
		//    if (NFLStat <= 21)
		//    {
		//        decimal ratio = (1.0m - 0.0m) / (10.0m - 21.0m);
		//        decimal coefficient = (NFLStat - 21.0m) * ratio + 0;
		//        return Math.Min(Math.Round(coefficient, 6), 1);
		//    }
		//    else if (NFLStat > 21)
		//    {
		//        decimal ratio = (0.0m - -1.0m) / (21.0m - 35.0m);
		//        decimal coefficient = (NFLStat - 35.0m) * ratio - 1;
		//        return Math.Max(Math.Round(coefficient, 6), -1);
		//    }
		//    else
		//    {
		//        //unreachable
		//        return 0;
		//    }
		//}

		//public decimal TurnoverDifferential(decimal NFLStat)
		//{
		//    if (NFLStat >= 0)
		//    {
		//        decimal ratio = (1.0m - 0.0m) / (40.0m - 0.0m);
		//        decimal coefficient = (NFLStat - 0.0m) * ratio + 0;
		//        return Math.Min(Math.Round(coefficient, 6), 1);
		//    }
		//    else if (NFLStat < 0)
		//    {
		//        decimal ratio = (0.0m - -1.0m) / (0.0m - -40.0m);
		//        decimal coefficient = (NFLStat - -40.0m) * ratio - 1;
		//        return Math.Max(Math.Round(coefficient, 6), -1);
		//    }
		//    else
		//    {
		//        //unreachable
		//        return 0;
		//    }
		//}

		//public decimal redzonePercentageOffense(decimal NFLStat)
		//{
		//    if (NFLStat >= 35)
		//    {
		//        decimal ratio = (1.0m - 0.0m) / (75.00m - 35.00m);
		//        decimal coefficient = (NFLStat - 35.00m) * ratio + 0;
		//        return Math.Min(Math.Round(coefficient, 6), 1);
		//    }
		//    else if (NFLStat < 35)
		//    {
		//        decimal ratio = (0.0m - -1.0m) / (35.00m - 15.00m);
		//        decimal coefficient = (NFLStat - 15.00m) * ratio - 1;
		//        return Math.Max(Math.Round(coefficient, 6), -1);
		//    }
		//    else
		//    {
		//        //unreachable
		//        return 0;
		//    }
		//}

		//public decimal redZonePercentageDefense(decimal NFLStat)
		//{
		//    if (NFLStat <= 50)
		//    {
		//        decimal ratio = (1.0m - 0.0m) / (30.00m - 50.00m);
		//        decimal coefficient = (NFLStat - 50.00m) * ratio + 0;
		//        return Math.Min(Math.Round(coefficient, 6), 1);
		//    }
		//    else if (NFLStat > 35)
		//    {
		//        decimal ratio = (0.0m - -1.0m) / (50.00m - 75.00m);
		//        decimal coefficient = (NFLStat - 75.0m) * ratio - 1;
		//        return Math.Max(Math.Round(coefficient, 6), -1);
		//    }
		//    else
		//    {
		//        //unreachable
		//        return 0;
		//    }
		//}


		//public decimal LPCoefficient(LOMBARDISPICK.Model.LPCoefficient StatsFromUser)
		//{
		//    return (((this.PasserRating(StatsFromUser.PasserRating) + this.PointsPerGameOffense(StatsFromUser.PointsPerGameOffense) + this.PointsPerGameDefense(StatsFromUser.PointsPerGameDefense) + this.TurnoverDifferential(StatsFromUser.TurnoverDifferential) + this.redzonePercentageOffense(StatsFromUser.redzonePercentageOffense) + this.redZonePercentageDefense(StatsFromUser.redZonePercentageDefense)
		//   ) /6) * 100) ;
		//}


		const String Winner = "Winner";
		const String RunnerUp = "RunnerUp";
		const String No = "No";
		//example from http://weka.wikispaces.com/IKVM+with+Weka+tutorial
		//and from http://stackoverflow.com/questions/9616872/classification-of-instances-in-weka
		//http://weka.wikispaces.com/Adding+attributes+to+a+dataset
		public List<LPWekaPrediction> CalculateWeka(int seasonUsed, LPCoefficient dataFromUser)
		{
			//fix out of bounds for 2000
			if (seasonUsed == 2012)
			{
				seasonUsed = 2011;
			}

			//var CustomerService = DependencyResolver.Current.GetService<INFLTeamsService>();

			//Create user input instance
			FastVector atts;
			FastVector attsRel;
			FastVector attValsTeam;
			FastVector attValsSupperBowlWinners;
			FastVector attValsOffRank;
			FastVector attValsDefRank;
			string predString = "";
			var OffDeffStats = DependencyResolver.Current.GetService<IPREDICTION_OFFENSE_DEFENSE_STATSService>();

			Instances TestInst;
			Instances dataRel;
			double[] vals;
			double[] valsRel;

			// 1. set up attributes
			atts = new FastVector();
			// - numeric
			atts.addElement(new weka.core.Attribute("Score"));
			atts.addElement(new weka.core.Attribute("PasserRating"));
			atts.addElement(new weka.core.Attribute("TurnoverDifferential"));
			atts.addElement(new weka.core.Attribute("RedZoneConversionPercentage"));
			atts.addElement(new weka.core.Attribute("Percentage"));
			atts.addElement(new weka.core.Attribute("DivisionWins"));
			atts.addElement(new weka.core.Attribute("ConferenceWins"));
			atts.addElement(new weka.core.Attribute("NetPoints"));
			atts.addElement(new weka.core.Attribute("Season"));
			atts.addElement(new weka.core.Attribute("OpponentScore"));
			atts.addElement(new weka.core.Attribute("TimeOfPosession"));
			atts.addElement(new weka.core.Attribute("Touchdowns"));
			atts.addElement(new weka.core.Attribute("RushingAttempts"));
			atts.addElement(new weka.core.Attribute("PassingAttempts "));
			atts.addElement(new weka.core.Attribute("PassingYardsPerAttempt"));
			atts.addElement(new weka.core.Attribute("ThirdDownPercentage"));
			atts.addElement(new weka.core.Attribute("FourthDownPercentage"));
			atts.addElement(new weka.core.Attribute("RedZoneAttempts"));
			atts.addElement(new weka.core.Attribute("RedZoneConversions"));
			atts.addElement(new weka.core.Attribute("GoalToGoAttempts"));
			atts.addElement(new weka.core.Attribute("GoalToGoConversions"));
			atts.addElement(new weka.core.Attribute("Penalties"));
			atts.addElement(new weka.core.Attribute("PenaltyYards"));
			atts.addElement(new weka.core.Attribute("TimesSacked"));
			atts.addElement(new weka.core.Attribute("TimesSackedYards"));
			atts.addElement(new weka.core.Attribute("QuarterbackHits"));
			atts.addElement(new weka.core.Attribute("OpponentTimeOfPosession"));
			atts.addElement(new weka.core.Attribute("OpponentTouchdowns"));
			atts.addElement(new weka.core.Attribute("OpponentRushingAttempts"));
			atts.addElement(new weka.core.Attribute("OpponentPassingAttempts"));
			atts.addElement(new weka.core.Attribute("OpponentPassingYardsPerAttempt"));
			atts.addElement(new weka.core.Attribute("OpponentPasserRating"));
			atts.addElement(new weka.core.Attribute("OpponentThirdDownPercentage"));
			atts.addElement(new weka.core.Attribute("OpponentFourthDownPercentage"));
			atts.addElement(new weka.core.Attribute("OpponentRedZoneAttempts"));
			atts.addElement(new weka.core.Attribute("OpponentRedZoneConversions"));
			atts.addElement(new weka.core.Attribute("OpponentGoalToGoAttempts"));
			atts.addElement(new weka.core.Attribute("OpponentGoalToGoConversions"));
			atts.addElement(new weka.core.Attribute("OpponentPenalties"));
			atts.addElement(new weka.core.Attribute("OpponentPenaltyYards"));
			atts.addElement(new weka.core.Attribute("OpponentTimesSacked"));
			atts.addElement(new weka.core.Attribute("OpponentTimesSackedYards"));
			atts.addElement(new weka.core.Attribute("Punts"));
			atts.addElement(new weka.core.Attribute("OpponentPunts"));
			atts.addElement(new weka.core.Attribute("OpponentTurnoverDifferential"));
			atts.addElement(new weka.core.Attribute("TeamSeasonID"));
			atts.addElement(new weka.core.Attribute("OpponentRedZoneConversionsPercentage"));

			// - string
			//atts.addElement(new weka.core.Attribute("Team", (FastVector)null));

			// - nominal
			attValsTeam = new FastVector();
			foreach (var x in this.nflTeamsService.getAllSorted())
			{
				attValsTeam.addElement(x.TeamNameAbbreviations);
			}
			atts.addElement(new weka.core.Attribute("Team", attValsTeam));

			attValsSupperBowlWinners = new FastVector();
			attValsSupperBowlWinners.addElement(Winner);
			attValsSupperBowlWinners.addElement(RunnerUp);
			attValsSupperBowlWinners.addElement(No);
			atts.addElement(new weka.core.Attribute("SuperBowlResult", attValsSupperBowlWinners));

			// 2. create Instances object
			TestInst = new Instances("MyRelation", atts, 0);

			// 3. fill with data supplied by user to create test instance.
			foreach (var x in teamSeasonService.getAllSorted())
			{
				if (seasonUsed == x.Season && this.nflTeamsService.getById(dataFromUser.NFLTeamsID).TeamNameAbbreviations != x.NFLTeam.TeamNameAbbreviations)
				{
					vals = new double[TestInst.numAttributes()];
					// - numeric
					vals[0] = x.Score;
					vals[1] = x.PasserRating;
					vals[2] = x.TurnoverDifferential;
					vals[3] = (double)x.RedZoneConversionPercentage;
					vals[4] = Utils.missingValue();
					vals[5] = Utils.missingValue();
					vals[6] = Utils.missingValue();
					vals[7] = Utils.missingValue();
					vals[8] = x.Season;
					vals[9] = x.OpponentScore;
					vals[10] = x.TimeOfPosession;
					vals[11] = Utils.missingValue();
					vals[12] = Utils.missingValue();
					vals[13] = Utils.missingValue();
					vals[14] = x.PassingYardsPerAttempt;
					vals[15] = x.ThirdDownPercentage;
					vals[16] = x.FourthDownPercentage;
					vals[17] = Utils.missingValue();
					vals[18] = Utils.missingValue();
					vals[19] = Utils.missingValue();
					vals[20] = Utils.missingValue();
					vals[21] = x.Penalties;
					vals[22] = x.PenaltyYards;
					vals[23] = x.TimesSacked;
					vals[24] = x.TimesSackedYards;
					vals[25] = x.QuarterbackHits;
					vals[26] = x.OpponentTimeOfPosession;
					vals[27] = Utils.missingValue();
					vals[28] = Utils.missingValue();
					vals[29] = Utils.missingValue();
					vals[30] = x.OpponentPassingYardsPerAttempt;
					vals[31] = x.OpponentPasserRating;
					vals[32] = x.OpponentThirdDownPercentage;
					vals[33] = x.OpponentFourthDownPercentage;
					vals[34] = Utils.missingValue();
					vals[35] = Utils.missingValue();
					vals[36] = Utils.missingValue();
					vals[37] = Utils.missingValue();
					vals[38] = x.OpponentPenalties;
					vals[39] = x.OpponentPenaltyYards;
					vals[40] = x.OpponentTimesSacked;
					vals[41] = x.OpponentTimesSackedYards;
					vals[42] = x.Punts;
					vals[43] = x.OpponentPunts;
					vals[44] = x.OpponentTurnoverDifferential;
					vals[45] = Utils.missingValue();
					vals[46] = (double)x.OpponentRedZoneConversionsPercentage;

					vals[47] = attValsTeam.indexOf(x.NFLTeam.TeamNameAbbreviations);
					// - nominal
					//vals[4] = attValsTeam.indexOf(this.nflTeamsService.getById(x.NFLTeamsID).TeamNameAbbreviations);
					vals[48] = Utils.missingValue();
					// add
					TestInst.add(new DenseInstance(1.0, vals));
				}
				else if (seasonUsed == x.Season && this.nflTeamsService.getById(dataFromUser.NFLTeamsID).TeamNameAbbreviations == x.NFLTeam.TeamNameAbbreviations)
				{
					vals = new double[TestInst.numAttributes()];
					// - numeric
					vals[0] = (double)dataFromUser.PointsPerGameOffense * 16;
					vals[1] = (double)dataFromUser.PasserRating;
					vals[2] = (double)dataFromUser.TurnoverDifferential;
					vals[3] = (double)dataFromUser.redzonePercentageOffense;
					vals[4] = Utils.missingValue();
					vals[5] = Utils.missingValue();
					vals[6] = Utils.missingValue();
					vals[7] = Utils.missingValue();
					vals[8] = x.Season;
					vals[9] = (double)dataFromUser.PointsPerGameDefense *16;
					vals[10] = (double)dataFromUser.TimeOfPosession;
					vals[11] = Utils.missingValue();
					vals[12] = Utils.missingValue();
					vals[13] = Utils.missingValue();
					vals[14] = (double)dataFromUser.PassingYardsPerAttempt;
					vals[15] = (double)dataFromUser.ThirdDownPercentage;
					vals[16] = (double)dataFromUser.FourthDownPercentage;
					vals[17] = Utils.missingValue();
					vals[18] = Utils.missingValue();
					vals[19] = Utils.missingValue();
					vals[20] = Utils.missingValue();
					vals[21] = (double)dataFromUser.Penalties;
					vals[22] = (double)dataFromUser.PenaltyYards;
					vals[23] = (double)dataFromUser.TimesSacked;
					vals[24] = (double)dataFromUser.TimesSackedYards;
					vals[25] = (double)dataFromUser.QuarterbackHits;
					vals[26] = (double)dataFromUser.OpponentTimeOfPosession;
					vals[27] = Utils.missingValue();
					vals[28] = Utils.missingValue();
					vals[29] = Utils.missingValue();
					vals[30] = (double)dataFromUser.OpponentPassingYardsPerAttempt;
					vals[31] = (double)dataFromUser.OpponentPasserRating;
					vals[32] = (double)dataFromUser.OpponentThirdDownPercentage;
					vals[33] = (double)dataFromUser.OpponentFourthDownPercentage;
					vals[34] = Utils.missingValue();
					vals[35] = Utils.missingValue();
					vals[36] = Utils.missingValue();
					vals[37] = Utils.missingValue();
					vals[38] = (double)dataFromUser.OpponentPenalties;
					vals[39] = (double)dataFromUser.OpponentPenaltyYards;
					vals[40] = (double)dataFromUser.OpponentTimesSacked;
					vals[41] = (double)dataFromUser.OpponentTimesSackedYards;
					vals[42] = (double)dataFromUser.Punts;
					vals[43] = (double)dataFromUser.OpponentPunts;
					vals[44] = (double)dataFromUser.OpponentTurnoverDifferential;
					vals[45] = Utils.missingValue();
					vals[46] = (double)dataFromUser.redZonePercentageDefense;

					vals[47] = attValsTeam.indexOf(x.NFLTeam.TeamNameAbbreviations);
					// - nominal
					//vals[4] = attValsTeam.indexOf(this.nflTeamsService.getMany(y => y.TeamNameAbbreviations == "PHI").SingleOrDefault().TeamNameAbbreviations);
					vals[48] = Utils.missingValue();
					// add
					TestInst.add(new DenseInstance(1.0, vals));
				}
			}

			var dataString = TestInst.toString();



			//Training Set
			List<int> SeasonList = new List<int>();

			//Perform a split on dataset ensuring that the year being calculated is excluded from the dataset.
			//years 2001 to 2011
			for (int i = 2001; i < 2012; i++){
				if (i != seasonUsed)
				{
					SeasonList.Add(i);
				}
			}
			Instances data = trainClassifierTeamSeason(SeasonList);

            return LPWekaPrediction(data, TestInst, attValsSupperBowlWinners, dataFromUser.YearToCalculate);
		}


        public List<LPWekaPrediction> LPWekaPrediction(Instances trainData, Instances TestInst, FastVector attValsSupperBowlWinners, int YearToCalculate)
        {

            List<LPWekaPrediction> LPWekaPredictionList = new List<LPWekaPrediction>();

            try
            {
                weka.core.Instances insts = trainData;
                insts.setClassIndex(insts.numAttributes() - 1);

                //http://weka.wikispaces.com/Use+WEKA+in+your+Java+code
                //weka.classifiers.Classifier cl = new weka.classifiers.trees.J48();
                weka.classifiers.Classifier cl = new weka.classifiers.bayes.NaiveBayesUpdateable();

                //randomize the order of the instances in the dataset.
                weka.filters.Filter myRandom = new weka.filters.unsupervised.instance.Randomize();
                myRandom.setInputFormat(insts);
                insts = weka.filters.Filter.useFilter(insts, myRandom);

                //weka.filters.Filter myRandomTest = new weka.filters.unsupervised.instance.Randomize();
                //myRandomTest.setInputFormat(TestInst);
                //TestInst = weka.filters.Filter.useFilter(TestInst, myRandomTest);

                int cIdx = insts.numAttributes() - 1;
                insts.setClassIndex(cIdx);

                cIdx = TestInst.numAttributes() - 1;
                TestInst.setClassIndex(cIdx);

                cl.buildClassifier(insts);
                weka.classifiers.Evaluation eTest = new weka.classifiers.Evaluation(insts);
                eTest.evaluateModel(cl, insts);
                String strSummary = eTest.toSummaryString().Replace("\n", "<br />");

                // Get the confusion matrix
                double[][] cmMatrix = eTest.confusionMatrix();

                for (int i = 0; i < TestInst.numInstances(); i++)
                {
                    double predictedClass = cl.classifyInstance(TestInst.instance(i));
                    double[] predictedScore = cl.distributionForInstance(TestInst.instance(i));

                    LPWekaPrediction LPWekaPredictionModel = new LPWekaPrediction();

                    LPWekaPredictionModel.strSummary = strSummary;
                    LPWekaPredictionModel.cmMatrix = cmMatrix;

                    for (int j = 0; j < 3; j++)
                    {
                        switch (attValsSupperBowlWinners.elementAt(j).ToString())
                        {
                            case "No":
                                {
                                    LPWekaPredictionModel.NoPrediction = Math.Round(predictedScore.ElementAt(j), 4, MidpointRounding.AwayFromZero);
                                    break;
                                }
                            case "RunnerUp":
                                {
                                    LPWekaPredictionModel.RunnerUpPrediction = Math.Round(predictedScore.ElementAt(j), 4, MidpointRounding.AwayFromZero);
                                    break;
                                }
                            case "Winner":
                                {
                                    LPWekaPredictionModel.WinPrediction = Math.Round(predictedScore.ElementAt(j), 4, MidpointRounding.AwayFromZero);
                                    break;
                                }
                        }
                    }

                    string currentAbbreviation = TestInst.instance(i).attribute(47).value(i);
                    LPWekaPredictionModel.TeamAbbreviation = TestInst.instance(i).attribute(47).value(i);
                    LPWekaPredictionModel.TeamName = this.nflTeamsService.getMany(x => x.TeamNameAbbreviations == currentAbbreviation).Select(x => x.TeamName).SingleOrDefault();
                    LPWekaPredictionModel.NFLTeamsID = this.nflTeamsService.getMany(x => x.TeamNameAbbreviations == currentAbbreviation).Select(x => x.NFLTeamsID).SingleOrDefault();
                    LPWekaPredictionModel.PredictionResult = TestInst.classAttribute().value((int)predictedClass);
                    LPWekaPredictionModel.YearToCalculate = YearToCalculate;

                    LPWekaPredictionList.Add(LPWekaPredictionModel);
                }
            }
            catch (java.lang.Exception ex)
            {
                ex.printStackTrace();
            }

            return LPWekaPredictionList;
        }





		//this is used for training classifiers.  Pass in the season years used to train this classifier.
		private weka.core.Instances trainClassifierTeamSeason(List<int> SeasonYearsUsedForTraining)
		{
			FastVector atts;
			FastVector attsRel;
			FastVector attValsTeam;
			FastVector attValsSupperBowlWinners;
			FastVector attValsOffRank;
			FastVector attValsDefRank;
			Instances data;
			Instances dataRel;
			double[] vals;
			double[] valsRel;
			var OffDeffStats = DependencyResolver.Current.GetService<IPREDICTION_OFFENSE_DEFENSE_STATSService>();


			// 1. set up attributes
			atts = new FastVector();
			// - numeric
			atts.addElement(new weka.core.Attribute("Score"));
			atts.addElement(new weka.core.Attribute("PasserRating"));
			atts.addElement(new weka.core.Attribute("TurnoverDifferential"));
			atts.addElement(new weka.core.Attribute("RedZoneConversionPercentage"));
			atts.addElement(new weka.core.Attribute("Percentage"));
			atts.addElement(new weka.core.Attribute("DivisionWins"));
			atts.addElement(new weka.core.Attribute("ConferenceWins"));
			atts.addElement(new weka.core.Attribute("NetPoints"));
			atts.addElement(new weka.core.Attribute("Season"));
			atts.addElement(new weka.core.Attribute("OpponentScore"));
			atts.addElement(new weka.core.Attribute("TimeOfPosession"));
			atts.addElement(new weka.core.Attribute("Touchdowns"));
			atts.addElement(new weka.core.Attribute("RushingAttempts"));
			atts.addElement(new weka.core.Attribute("PassingAttempts "));
			atts.addElement(new weka.core.Attribute("PassingYardsPerAttempt"));
			atts.addElement(new weka.core.Attribute("ThirdDownPercentage"));
			atts.addElement(new weka.core.Attribute("FourthDownPercentage"));
			atts.addElement(new weka.core.Attribute("RedZoneAttempts"));
			atts.addElement(new weka.core.Attribute("RedZoneConversions"));
			atts.addElement(new weka.core.Attribute("GoalToGoAttempts"));
			atts.addElement(new weka.core.Attribute("GoalToGoConversions"));
			atts.addElement(new weka.core.Attribute("Penalties"));
			atts.addElement(new weka.core.Attribute("PenaltyYards"));
			atts.addElement(new weka.core.Attribute("TimesSacked"));
			atts.addElement(new weka.core.Attribute("TimesSackedYards"));
			atts.addElement(new weka.core.Attribute("QuarterbackHits"));
			atts.addElement(new weka.core.Attribute("OpponentTimeOfPosession"));
			atts.addElement(new weka.core.Attribute("OpponentTouchdowns"));
			atts.addElement(new weka.core.Attribute("OpponentRushingAttempts"));
			atts.addElement(new weka.core.Attribute("OpponentPassingAttempts"));
			atts.addElement(new weka.core.Attribute("OpponentPassingYardsPerAttempt"));
			atts.addElement(new weka.core.Attribute("OpponentPasserRating"));
			atts.addElement(new weka.core.Attribute("OpponentThirdDownPercentage"));
			atts.addElement(new weka.core.Attribute("OpponentFourthDownPercentage"));
			atts.addElement(new weka.core.Attribute("OpponentRedZoneAttempts"));
			atts.addElement(new weka.core.Attribute("OpponentRedZoneConversions"));
			atts.addElement(new weka.core.Attribute("OpponentGoalToGoAttempts"));
			atts.addElement(new weka.core.Attribute("OpponentGoalToGoConversions"));
			atts.addElement(new weka.core.Attribute("OpponentPenalties"));
			atts.addElement(new weka.core.Attribute("OpponentPenaltyYards"));
			atts.addElement(new weka.core.Attribute("OpponentTimesSacked"));
			atts.addElement(new weka.core.Attribute("OpponentTimesSackedYards"));
			atts.addElement(new weka.core.Attribute("Punts"));
			atts.addElement(new weka.core.Attribute("OpponentPunts"));
			atts.addElement(new weka.core.Attribute("OpponentTurnoverDifferential"));
			atts.addElement(new weka.core.Attribute("TeamSeasonID"));
			atts.addElement(new weka.core.Attribute("OpponentRedZoneConversionsPercentage"));
			
			// - string
			//atts.addElement(new weka.core.Attribute("Team", (FastVector)null));

			// - nominal
			attValsTeam = new FastVector();
			foreach (var x in this.nflTeamsService.getAllSorted())
			{
				attValsTeam.addElement(x.TeamNameAbbreviations);
			}
			atts.addElement(new weka.core.Attribute("Team", attValsTeam));

			attValsSupperBowlWinners = new FastVector();
			attValsSupperBowlWinners.addElement(Winner);
			attValsSupperBowlWinners.addElement(RunnerUp);
			attValsSupperBowlWinners.addElement(No);
			atts.addElement(new weka.core.Attribute("SuperBowlResult", attValsSupperBowlWinners));

			//attValsOffRank = new FastVector();
			//for (int i = 0; i < 32; i++)
			//{
			//    attValsOffRank.addElement(i.ToString());
			//}
			//atts.addElement(new weka.core.Attribute("OffensiveRankings", attValsOffRank));

			//attValsOffRank = new FastVector();
			//for (int i = 0; i < 32; i++)
			//{
			//    attValsOffRank.addElement(i.ToString());
			//}
			//atts.addElement(new weka.core.Attribute("DefensiveRankings", attValsOffRank));

			// 2. create Instances object
			data = new Instances("MyRelation", atts, 0);

			// 3. fill with data
			// loop to create instances
			foreach (var x in teamSeasonService.getAllSorted())
			{
				if (SeasonYearsUsedForTraining.Contains(x.Season))
				{
					var SupBowlWin = x.NFLTeam.Standings.Where(y => y.Season == x.Season && y.NFLTeamsID == x.NFLTeamsID).Select(y => y.SuperBowlWinner).SingleOrDefault();
					var SupBowlSecond = x.NFLTeam.Standings.Where(y => y.Season == x.Season && y.NFLTeamsID == x.NFLTeamsID).Select(y => y.SuperBowlRunnerUp).SingleOrDefault();

					vals = new double[data.numAttributes()];
					// - numeric
					vals[0] = x.Score;
					vals[1] = x.PasserRating;
					vals[2] = x.TurnoverDifferential;
					vals[3] = (double)x.RedZoneConversionPercentage;
					vals[4] = (double)x.NFLTeam.Standings.Where(y => y.Season == x.Season && y.NFLTeamsID == x.NFLTeamsID).Select(y => y.Percentage).SingleOrDefault();
					vals[5] = (int)x.NFLTeam.Standings.Where(y => y.Season == x.Season && y.NFLTeamsID == x.NFLTeamsID).Select(y => y.DivisionWins).SingleOrDefault();
					vals[6] = (int)x.NFLTeam.Standings.Where(y => y.Season == x.Season && y.NFLTeamsID == x.NFLTeamsID).Select(y => y.ConferenceWins).SingleOrDefault();
					vals[7] = (int)x.NFLTeam.Standings.Where(y => y.Season == x.Season && y.NFLTeamsID == x.NFLTeamsID).Select(y => y.NetPoints).SingleOrDefault();

					vals[8] = x.Season;
					vals[9] = x.OpponentScore;
					vals[10] = x.TimeOfPosession;
					vals[11] = x.Touchdowns;
					vals[12] = x.RushingAttempts;
					vals[13] = x.PassingAttempts;
					vals[14] = x.PassingYardsPerAttempt;
					vals[15] = x.ThirdDownPercentage;
					vals[16] = x.FourthDownPercentage;
					vals[17] = x.RedZoneAttempts;
					vals[18] = x.RedZoneConversions;
					vals[19] = x.GoalToGoAttempts;
					vals[20] = x.GoalToGoConversions;
					vals[21] = x.Penalties;
					vals[22] = x.PenaltyYards;
					vals[23] = x.TimesSacked;
					vals[24] = x.TimesSackedYards;
					vals[25] = x.QuarterbackHits;
					vals[26] = x.OpponentTimeOfPosession;
					vals[27] = x.OpponentTouchdowns;
					vals[28] = x.OpponentRushingAttempts;
					vals[29] = x.OpponentPassingAttempts;
					vals[30] = x.OpponentPassingYardsPerAttempt;
					vals[31] = x.OpponentPasserRating;
					vals[32] = x.OpponentThirdDownPercentage;
					vals[33] = x.OpponentFourthDownPercentage;
					vals[34] = x.OpponentRedZoneAttempts;
					vals[35] = x.OpponentRedZoneConversions;
					vals[36] = x.OpponentGoalToGoAttempts;
					vals[37] = x.OpponentGoalToGoConversions;
					vals[38] = x.OpponentPenalties;
					vals[39] = x.OpponentPenaltyYards;
					vals[40] = x.OpponentTimesSacked;
					vals[41] = x.OpponentTimesSackedYards;
					vals[42] = x.Punts;
					vals[43] = x.OpponentPunts;
					vals[44] = x.OpponentTurnoverDifferential;
					vals[45] = x.TeamSeasonID;
					vals[46] = (double)x.OpponentRedZoneConversionsPercentage;

					//vals[7] = data.attribute(7).addStringValue(x.NFLTeam.TeamNameAbbreviations);
					vals[47] = attValsTeam.indexOf(x.NFLTeam.TeamNameAbbreviations);
					// - nominal
					if (SupBowlWin == false && SupBowlSecond == false)
					{
						vals[48] = attValsSupperBowlWinners.indexOf("No");
					}
					else if (SupBowlWin == true)
					{
						vals[48] = attValsSupperBowlWinners.indexOf("Winner");
					}
					else if (SupBowlSecond == true)
					{
						vals[48] = attValsSupperBowlWinners.indexOf("RunnerUp");
					}
					//vals[4] = attValsTeam.indexOf(this.nflTeamsService.getById(x.NFLTeamsID).TeamNameAbbreviations);
					// add
					data.add(new DenseInstance(1.0, vals));
				}
			}
			var dataString = data.toString();
			return data;
		}





		/// <summary>
		///	Return the extra hours for a job version
		/// </summary>	
		public IEnumerable<string[]> getDefaultStatsForTeam(List<int> foreignKeyCondition)
		{
			int nflTeamID = foreignKeyCondition[0];
			int SeasonID = foreignKeyCondition[1];
			if (SeasonID == 2012)
			{
				SeasonID = 2011;
			}
			var currentTeamStats = this.nflTeamsService.getById(foreignKeyCondition[0]);
			var currentTeamSeasonStats = this.teamSeasonService.getManySorted(x => x.NFLTeamsID == nflTeamID && x.Season == SeasonID).SingleOrDefault();
			
			List<String[]> StatsList = new List<String[]>();

			StatsList.Add(new string[] { "JSON_STATS", "YearToCalculate", foreignKeyCondition[1].ToString()});
			StatsList.Add(new string[] { "JSON_STATS", "NFLTeamsID", foreignKeyCondition[0].ToString()});
			StatsList.Add(new string[] { "JSON_STATS", "PasserRating", currentTeamSeasonStats.PasserRating.ToString()});
			StatsList.Add(new string[] { "JSON_STATS", "PointsPerGameOffense", (currentTeamSeasonStats.Score/16).ToString() });
			StatsList.Add(new string[] { "JSON_STATS", "PointsPerGameDefense", (currentTeamSeasonStats.OpponentScore/16).ToString() });
			StatsList.Add(new string[] { "JSON_STATS", "TurnoverDifferential", currentTeamSeasonStats.TurnoverDifferential.ToString() });
			StatsList.Add(new string[] { "JSON_STATS", "redzonePercentageOffense", currentTeamSeasonStats.RedZoneConversionPercentage.ToString() });
			StatsList.Add(new string[] { "JSON_STATS", "redZonePercentageDefense", currentTeamSeasonStats.OpponentRedZoneConversionsPercentage.ToString() });
			StatsList.Add(new string[] { "JSON_STATS", "TimeOfPosession", currentTeamSeasonStats.TimeOfPosession.ToString() });
			StatsList.Add(new string[] { "JSON_STATS", "PassingYardsPerAttempt", currentTeamSeasonStats.OpponentPassingYardsPerAttempt.ToString() });
			StatsList.Add(new string[] { "JSON_STATS", "ThirdDownPercentage", currentTeamSeasonStats.ThirdDownPercentage.ToString() });
			StatsList.Add(new string[] { "JSON_STATS", "FourthDownPercentage", currentTeamSeasonStats.FourthDownPercentage.ToString() });
			StatsList.Add(new string[] { "JSON_STATS", "Penalties", currentTeamSeasonStats.Penalties.ToString() });
			StatsList.Add(new string[] { "JSON_STATS", "PenaltyYards", currentTeamSeasonStats.PenaltyYards.ToString() });
			StatsList.Add(new string[] { "JSON_STATS", "TimesSacked", currentTeamSeasonStats.TimesSacked.ToString() });
			StatsList.Add(new string[] { "JSON_STATS", "TimesSackedYards", currentTeamSeasonStats.TimesSackedYards.ToString() });
			StatsList.Add(new string[] { "JSON_STATS", "QuarterbackHits", currentTeamSeasonStats.QuarterbackHits.ToString() });
			StatsList.Add(new string[] { "JSON_STATS", "OpponentTimeOfPosession", currentTeamSeasonStats.OpponentTimeOfPosession.ToString() });
			StatsList.Add(new string[] { "JSON_STATS", "OpponentPassingYardsPerAttempt", currentTeamSeasonStats.OpponentPassingYardsPerAttempt.ToString() });
			StatsList.Add(new string[] { "JSON_STATS", "OpponentPasserRating", currentTeamSeasonStats.OpponentPasserRating.ToString() });
			StatsList.Add(new string[] { "JSON_STATS", "OpponentThirdDownPercentage", currentTeamSeasonStats.OpponentThirdDownPercentage.ToString() });
			StatsList.Add(new string[] { "JSON_STATS", "OpponentFourthDownPercentage", currentTeamSeasonStats.OpponentFourthDownPercentage.ToString() });
			StatsList.Add(new string[] { "JSON_STATS", "OpponentPenalties", currentTeamSeasonStats.OpponentPenalties.ToString() });
			StatsList.Add(new string[] { "JSON_STATS", "OpponentPenaltyYards", currentTeamSeasonStats.OpponentPenaltyYards.ToString() });
			StatsList.Add(new string[] { "JSON_STATS", "OpponentTimesSacked", currentTeamSeasonStats.OpponentTimesSacked.ToString() });
			StatsList.Add(new string[] { "JSON_STATS", "OpponentTimesSackedYards", currentTeamSeasonStats.OpponentTimesSackedYards.ToString() });
			StatsList.Add(new string[] { "JSON_STATS", "Punts", currentTeamSeasonStats.Punts.ToString() });
			StatsList.Add(new string[] { "JSON_STATS", "OpponentPunts", currentTeamSeasonStats.OpponentPunts.ToString() });
			StatsList.Add(new string[] { "JSON_STATS", "OpponentTurnoverDifferential", currentTeamSeasonStats.OpponentTurnoverDifferential.ToString() });

			return StatsList.AsEnumerable();
		}







		//public double testWeka()
		//{
		//    try
		//    {
		//        weka.core.
		//        TokenPair[] dataset = this.nflTeamsService.getAllSorted().ToArray();
		//        FastVector fv = CreateFastVector(dataset);
		//        TextReader

		//        weka.core.Instances insts = new weka.core.Instances("Rel",dataset,10);
		//        insts.setClassIndex(insts.numAttributes() - 1);

		//        weka.classifiers.Classifier cl = new weka.classifiers.trees.J48();
		//        Console.WriteLine("Performing " + percentSplit + "% split evaluation.");

		//        //randomize the order of the instances in the dataset.
		//        weka.filters.Filter myRandom = new weka.filters.unsupervised.instance.Randomize();
		//        myRandom.setInputFormat(insts);
		//        insts = weka.filters.Filter.useFilter(insts, myRandom);

		//        int trainSize = insts.numInstances() * percentSplit / 100;
		//        int testSize = insts.numInstances() - trainSize;
		//        weka.core.Instances train = new weka.core.Instances(insts, 0, trainSize);

		//        cl.buildClassifier(train);
		//        int numCorrect = 0;
		//        for (int i = trainSize; i < insts.numInstances(); i++)
		//        {
		//            weka.core.Instance currentInst = insts.instance(i);
		//            double predictedClass = cl.classifyInstance(currentInst);
		//            if (predictedClass == insts.instance(i).classValue())
		//                numCorrect++;
		//        }
		//        Console.WriteLine(numCorrect + " out of " + testSize + " correct (" +
		//                   (double)((double)numCorrect / (double)testSize * 100.0) + "%)");
		//    }
		//    catch (java.lang.Exception ex)
		//    {
		//        ex.printStackTrace();
		//    }
		//    return 0;
		//}


		//// This creates the data set's attributes vector
		//private FastVector CreateFastVector(TokenPair[] pairs)
		//{
		//    var fv = new FastVector();

		//    foreach (var attribute in _features)
		//    {
		//        Attribute att;
		//        if (attribute.Type.Equals(ArffType.Nominal))
		//        {
		//            var values = new FastVector();
		//            ExtractValues(values, pairs, attribute.FeatureName);
		//            att = new Attribute(attribute.FeatureName, values);
		//        }
		//        else
		//            att = new Attribute(attribute.FeatureName);

		//        fv.addElement(att);
		//    }

		//    {
		//        var classValues = new FastVector(2);
		//        classValues.addElement("0");
		//        classValues.addElement("1");
		//        var classAttribute = new Attribute("isCoref", classValues);
		//        fv.addElement(classAttribute);
		//    }

		//    return fv;
		//}




		//OFFENSIVE
		//public decimal ScoringPercentRank(decimal NFLStat)
		//{
		//    return 0;
		//}

		//public decimal ScoringRank(decimal NFLStat)
		//{
		//    return 0;
		//}
			
		//public decimal TotalPoints(decimal NFLStat)
		//{
		//    return 0;
		//}
			
		//public decimal AveragePointsPerGame(decimal NFLStat)
		//{
		//    return 0;
		//}
		
		//public decimal RedZonePercentage(decimal NFLStat)
		//{
		//    return 0;
		//}

		//public decimal PassingYardsPerAttempt(decimal NFLStat)
		//{
		//    return 0;
		//}

		////DEFENSIVE
		//public decimal DefensivePercentRank(decimal NFLStat)
		//{
		//    return 0;
		//}

		//public decimal DefensiveRank(decimal NFLStat)
		//{
		//    return 0;
		//}

		//public decimal TotalPointsAllowed(decimal NFLStat)
		//{
		//    return 0;
		//}

		//public decimal AveragePointsAllowedPerGame(decimal NFLStat)
		//{
		//    return 0;
		//}

		//public decimal DefensiveRedZonePercentage(decimal NFLStat)
		//{
		//    return 0;
		//}

	}

	public interface IPredictionService
	{
		////KEY STATS
		//decimal PasserRating(decimal NFLStat);
		//decimal PointsPerGameOffense(decimal NFLStat);
		//decimal PointsPerGameDefense(decimal NFLStat);
		//decimal TurnoverDifferential(decimal NFLStat);
		//decimal redzonePercentageOffense(decimal NFLStat);
		//decimal redZonePercentageDefense(decimal NFLStat);

		//decimal LPCoefficient(LOMBARDISPICK.Model.LPCoefficient StatsFromUser);




		List<LPWekaPrediction> CalculateWeka(int seasonUsed, LPCoefficient dataFromUser);
		IEnumerable<string[]> getDefaultStatsForTeam(List<int> foreignKeyCondition);
        List<LPWekaPrediction> LPWekaPrediction(Instances trainData, Instances TestInst, FastVector attValsSupperBowlWinners, int YearToCalculate);



		////OFFENSIVE
		//decimal ScoringPercentRank(decimal NFLStat);
		//decimal ScoringRank(decimal NFLStat);
		//decimal TotalPoints(decimal NFLStat);
		//decimal AveragePointsPerGame(decimal NFLStat);
		//decimal RedZonePercentage(decimal NFLStat);
		//decimal PassingYardsPerAttempt(decimal NFLStat);
		////DEFENSIVE
		//decimal DefensivePercentRank(decimal NFLStat);
		//decimal DefensiveRank(decimal NFLStat);
		//decimal TotalPointsAllowed(decimal NFLStat);
		//decimal AveragePointsAllowedPerGame(decimal NFLStat);
		//decimal DefensiveRedZonePercentage(decimal NFLStat);
	}
}
